package com.mccree.server;

import com.mccree.handler.DiscardServerHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

/**
 * 丢弃任何传入的数据
 */
public class DiscardServer {
    private int port;

    public DiscardServer(int port) {
        this.port = port;
    }
    public void run()throws Exception{
        /**
         * NioEventLoopGroup是处理I / O操作的多线程事件循环。
         * NettyEventLoopGroup为不同类型的传输提供了各种实现。
         * 在此示例中，我们正在实现服务器端应用程序，因此NioEventLoopGroup将使用两个应用程序。
         * 第一个通常称为“老板”，接受传入的连接。第二个通常称为“工人”，一旦老板接受连接并将注册的连接注册给工人，便处理已接受连接的流量。
         * 使用多少线程以及如何将它们映射到创建的Channels取决于EventLoopGroup实现，甚至可以通过构造函数进行配置。
         */
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            /**
             * ServerBootstrap是设置服务器的帮助程序类。您可以Channel直接使用来设置服务器。
             * 但是，请注意，这是一个繁琐的过程，在大多数情况下您无需这样做。
             */
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup,workerGroup)
                    /**
                     * 在这里，我们指定使用NioServerSocketChannel用于实例化新类Channel以接受传入连接的类。
                     */
             .channel(NioServerSocketChannel.class)
                    /**
                     * 在此指定的处理程序将始终由新接受的评估Channel。
                     * 该ChannelInitializer是意要帮助用户配置一个新的特殊处理程序Channel。
                     * 您很可能希望通过添加一些处理程序（例如实现您的网络应用程序）来配置ChannelPipeline新程序的。
                     * 随着应用程序变得复杂，您可能会向管道中添加更多处理程序，并最终将此匿名类提取到顶级类中。
                     * ChannelDiscardServerHandler
                     */
             .childHandler(new ChannelInitializer<SocketChannel>() {
                 @Override
                 protected void initChannel(SocketChannel ch) throws Exception {
                     ch.pipeline().addLast(new DiscardServerHandler());
                 }
             })
                    /**
                     * 您还可以设置特定于Channel实现的参数。
                     * 我们正在编写一个TCP / IP服务器，因此我们可以设置套接字选项，例如tcpNoDelay和keepAlive。
                     * 请参考的apidocsChannelOption和特定的ChannelConfig实现以获取有关support的概述ChannelOption。
                     */
             .option(ChannelOption.SO_BACKLOG,128)
                    /**
                     * 你有没有注意到option()和childOption()？
                     * option()用于NioServerSocketChannel接受传入的连接。
                     * childOption()是针对Channel父级接受的ServerChannel，NioSocketChannel在这种情况下。
                     */
             .childOption(ChannelOption.SO_KEEPALIVE,true);

            //绑定并开始接受传入的连接。
            /**
             * 。剩下的就是绑定到端口并启动服务器。
             * 在这里，我们绑定到计算机8080中所有NIC（网络接口卡）的端口。
             * 现在，您可以bind()根据需要多次调用该方法（使用不同的绑定地址。）
             */
            ChannelFuture f = b.bind(port).sync();
            //等待服务器套接字关闭。
            //在此示例中，不会发生这种情况，但是您可以这样做
            //正常关闭服务器
            f.channel().closeFuture().sync();


        }finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception{
        int port = 8080;
        if (args.length>0){
            port = Integer.parseInt(args[0]);
        }
        new DiscardServer(port).run();
    }
}
